`timescale 1ns / 1ps

module ALU(
    input [31:0] AA,
    input [31:0] AB,
    input [4:0] shamt,
    input [3:0] Aop,
    input shmt,
    output [32:0] AO,
    output Ov
    );

    wire [4:0] dist = (shmt? shamt : AA[4:0]);

    assign AO = (Aop == 4'b0000)? (AA + AB):
                (Aop == 4'b0001)? (AA - AB):
                (Aop == 4'b0010)? (AA | AB):
                (Aop == 4'b0011)? (AB << dist):
                (Aop == 4'b0100)? (AB >> dist):
                (Aop == 4'b0101)? ({{32{AB[31]}}, AB} >>> dist):
                (Aop == 4'b0110)? (AA & AB):
                (Aop == 4'b0111)? (AA ^ AB):
                (Aop == 4'b1000)? ~(AA | AB):
                (Aop == 4'b1001)? ($signed(AA) < $signed(AB)):
                (Aop == 4'b1010)? ({1'b0, AA} < {1'b0, AB}):
                (Aop == 4'b1011)? ({AA[31], AA} + {AB[31], AB}):// ov
                (Aop == 4'b1100)? ({AA[31], AA} - {AB[31], AB}):// ov
                (Aop == 4'b1101)? (0):
                (Aop == 4'b1110)? (0):
                                  (0);

    assign Ov = ((Aop == 4'b1011 || Aop == 4'b1100) && (AO[32] ^ AO[31]));

endmodule
